"""
评分系统 - 评分相关模型
"""
from django.db import models
from django.contrib.auth import get_user_model
from django.core.validators import MinValueValidator, MaxValueValidator
from django.utils import timezone
from django.db.models import Avg, Count, Sum, StdDev, Variance
from decimal import Decimal

from apps.core.models import TimeStampedModel

User = get_user_model()


class GradingStandard(TimeStampedModel):
    """
    评分标准
    定义评分等级和标准
    """
    name = models.CharField('标准名称', max_length=100)
    description = models.TextField('描述', blank=True)

    # 等级设置 (JSON格式，包含评分等级)
    grade_levels = models.JSONField(
        '等级',
        default=dict,
        help_text='例如: {"A": {"min": 90, "max": 100}, "B": {"min": 80, "max": 89}}'
    )

    # 及格分数
    passing_score = models.DecimalField(
        '及格分',
        max_digits=5,
        decimal_places=2,
        default=Decimal('60.00'),
        validators=[MinValueValidator(0), MaxValueValidator(100)]
    )

    # 满分
    full_score = models.DecimalField(
        '满分',
        max_digits=5,
        decimal_places=2,
        default=Decimal('100.00'),
        validators=[MinValueValidator(1), MaxValueValidator(1000)]
    )

    # 是否为默认标准
    is_default = models.BooleanField('默认标准', default=False)

    # 适用范围
    scope = models.CharField(
        '适用范围',
        max_length=20,
        choices=[
            ('all', '全局'),
            ('course', '课程'),
            ('exam_type', '考试类型'),
            ('custom', '自定义'),
        ],
        default='all'
    )

    # 创建者
    creator = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='grading_standards',
        verbose_name='创建者'
    )

    # 是否启用
    is_active = models.BooleanField('是否启用', default=True)

    class Meta:
        db_table = 'grading_standards'
        verbose_name = '评分标准'
        verbose_name_plural = '评分标准'
        ordering = ['-is_default', 'name']
        unique_together = [['name', 'creator']]

    def __str__(self):
        return f"{self.name} (满分:{self.full_score})"

    def get_grade(self, score):
        """根据分数获取等级"""
        if not score or score < 0:
            return None

        for grade, criteria in self.grade_levels.items():
            min_score = criteria.get('min', 0)
            max_score = criteria.get('max', 100)
            if min_score <= score <= max_score:
                return grade

        return None

    def is_passing(self, score):
        """判断是否及格"""
        return score >= self.passing_score


class GradeSheet(TimeStampedModel):
    """
    成绩单
    用于管理考试成绩
    """
    title = models.CharField('成绩单标题', max_length=200)
    description = models.TextField('描述', blank=True)

    # 关联考试
    examination = models.ForeignKey(
        'examination.Examination',
        on_delete=models.CASCADE,
        related_name='grade_sheets',
        verbose_name='关联考试',
        null=True,
        blank=True
    )

    # 关联课程 (可选) - TODO: Implement courses app
    # course = models.ForeignKey(
    #     'courses.Course',
    #     on_delete=models.SET_NULL,
    #     related_name='grade_sheets',
    #     verbose_name='关联课程',
    #     null=True,
    #     blank=True
    # )

    # 评分标准
    grading_standard = models.ForeignKey(
        GradingStandard,
        on_delete=models.PROTECT,
        related_name='grade_sheets',
        verbose_name='评分标准'
    )

    # 成绩单状态
    status = models.CharField(
        '状态',
        max_length=20,
        choices=[
            ('draft', '草稿'),
            ('calculating', '计算中'),
            ('reviewed', '已审核'),
            ('published', '已发布'),
            ('archived', '已归档'),
        ],
        default='draft'
    )

    # 发布时间
    published_at = models.DateTimeField('发布时间', null=True, blank=True)

    # 统计信息 (JSON格式)
    statistics_data = models.JSONField('统计信息', default=dict, blank=True)

    # 创建者
    creator = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='created_grade_sheets',
        verbose_name='创建者'
    )

    # 审核者
    reviewer = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        related_name='reviewed_grade_sheets',
        verbose_name='审核者',
        null=True,
        blank=True
    )

    # 审核时间
    reviewed_at = models.DateTimeField('审核时间', null=True, blank=True)

    # 审核备注
    review_notes = models.TextField('审核备注', blank=True)

    class Meta:
        db_table = 'grade_sheets'
        verbose_name = '成绩单'
        verbose_name_plural = '成绩单'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['status']),
            models.Index(fields=['examination']),
            # models.Index(fields=['course']),  # TODO: Add when courses app is implemented
            models.Index(fields=['creator']),
        ]

    def __str__(self):
        return self.title

    def publish(self):
        """发布成绩单"""
        if self.status == 'reviewed':
            self.status = 'published'
            self.published_at = timezone.now()
            self.save(update_fields=['status', 'published_at'])

    def calculate_statistics(self):
        """计算成绩单统计信息"""
        grades = self.grades.all()

        if not grades.exists():
            return

        scores = [grade.final_score for grade in grades if grade.final_score is not None]

        if not scores:
            return

        # 基本统计
        total_count = grades.count()
        passed_count = grades.filter(is_passed=True).count()

        statistics = {
            'total_participants': total_count,
            'completed_count': len(scores),
            'passed_count': passed_count,
            'failed_count': total_count - passed_count,
            'pass_rate': (passed_count / total_count * 100) if total_count > 0 else 0,
            'average_score': sum(scores) / len(scores),
            'highest_score': max(scores),
            'lowest_score': min(scores),
            'median_score': sorted(scores)[len(scores) // 2] if scores else 0,
        }

        # 计算方差和标准差
        if len(scores) > 1:
            avg = statistics['average_score']
            variance = sum((x - avg) ** 2 for x in scores) / len(scores)
            statistics['variance'] = variance
            statistics['std_dev'] = variance ** 0.5

        # 等级分布
        grade_distribution = {}
        for grade in grades:
            level = grade.grade_level
            grade_distribution[level] = grade_distribution.get(level, 0) + 1

        statistics['grade_distribution'] = grade_distribution

        # 分数段分布
        score_ranges = {
            '90-100': 0,
            '80-89': 0,
            '70-79': 0,
            '60-69': 0,
            '0-59': 0,
        }

        for score in scores:
            if score >= 90:
                score_ranges['90-100'] += 1
            elif score >= 80:
                score_ranges['80-89'] += 1
            elif score >= 70:
                score_ranges['70-79'] += 1
            elif score >= 60:
                score_ranges['60-69'] += 1
            else:
                score_ranges['0-59'] += 1

        statistics['score_distribution'] = score_ranges

        self.statistics_data = statistics
        self.save(update_fields=['statistics_data'])


class Grade(TimeStampedModel):
    """
    成绩
    学生具体的考试成绩
    """
    # 关联成绩单
    grade_sheet = models.ForeignKey(
        GradeSheet,
        on_delete=models.CASCADE,
        related_name='grades',
        verbose_name='成绩单'
    )

    # 学生
    student = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='grades',
        verbose_name='学生'
    )

    # 关联考试场次 - 暂时修改为examination
    examination = models.ForeignKey(
        'examination.Examination',
        on_delete=models.CASCADE,
        related_name='exam_grades',
        verbose_name='考试场次',
        null=True,
        blank=True
    )

    # 原始分数
    raw_score = models.DecimalField(
        '原始分数',
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)]
    )

    # 最终分数 (原始分+调整分)
    final_score = models.DecimalField(
        '最终分数',
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)]
    )

    # 等级
    grade_level = models.CharField(
        '等级',
        max_length=10,
        blank=True
    )

    # 是否及格
    is_passed = models.BooleanField('是否及格', default=False)

    # 排名 (同类考试中)
    rank = models.PositiveIntegerField('排名', null=True, blank=True)

    # 百分位
    percentile = models.DecimalField(
        '百分位',
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0), MaxValueValidator(100)]
    )

    # 评语
    comments = models.TextField('评语', blank=True)

    # 调分原因
    adjustment_reason = models.TextField('调分说明', blank=True)

    # 调分人
    adjusted_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        related_name='adjusted_grades',
        verbose_name='调分人',
        null=True,
        blank=True
    )

    # 调分时间
    adjusted_at = models.DateTimeField('调分时间', null=True, blank=True)

    class Meta:
        db_table = 'grades'
        verbose_name = '成绩'
        verbose_name_plural = '成绩'
        ordering = ['-final_score']
        unique_together = [['grade_sheet', 'student']]
        indexes = [
            models.Index(fields=['student']),
            models.Index(fields=['examination']),
            models.Index(fields=['grade_level']),
            models.Index(fields=['is_passed']),
            models.Index(fields=['final_score']),
        ]

    def __str__(self):
        return f"{self.student.real_name} - {self.final_score or 0}分"

    def calculate_grade(self):
        """计算等级和是否及格"""
        if self.final_score is None:
            return

        standard = self.grade_sheet.grading_standard
        self.grade_level = standard.get_grade(float(self.final_score)) or 'F'
        self.is_passed = standard.is_passing(float(self.final_score))

        self.save(update_fields=['grade_level', 'is_passed'])

    def adjust_score(self, new_score, reason, adjusted_by):
        """调整分数"""
        old_score = self.final_score
        self.final_score = new_score
        self.adjustment_reason = f"原分数: {old_score} -> 新分数: {new_score}. {reason}"
        self.adjusted_by = adjusted_by
        self.adjusted_at = timezone.now()

        self.save(update_fields=[
            'final_score', 'adjustment_reason', 'adjusted_by', 'adjusted_at'
        ])

        # 重新计算等级
        self.calculate_grade()


class GradeComponent(TimeStampedModel):
    """
    成绩组成部分
    用于详细成绩记录 (如：平时成绩 + 期末成绩)
    """
    grade = models.ForeignKey(
        Grade,
        on_delete=models.CASCADE,
        related_name='components',
        verbose_name='成绩'
    )

    # 成分名称
    name = models.CharField('成分名称', max_length=100)

    # 成分权重
    weight = models.DecimalField(
        '权重',
        max_digits=3,
        decimal_places=2,
        validators=[MinValueValidator(0), MaxValueValidator(1)]
    )

    # 成分分数
    score = models.DecimalField(
        '分数',
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)]
    )

    # 满分
    max_score = models.DecimalField(
        '满分',
        max_digits=6,
        decimal_places=2,
        validators=[MinValueValidator(0)]
    )

    # 备注
    notes = models.TextField('备注', blank=True)

    class Meta:
        db_table = 'grade_components'
        verbose_name = '成绩组成'
        verbose_name_plural = '成绩组成'
        ordering = ['name']
        unique_together = [['grade', 'name']]

    def __str__(self):
        return f"{self.name}: {self.score or 0}/{self.max_score} (权重: {self.weight})"


class GradeAppeal(TimeStampedModel):
    """
    成绩申诉
    """
    grade = models.ForeignKey(
        Grade,
        on_delete=models.CASCADE,
        related_name='appeals',
        verbose_name='成绩'
    )

    # 申诉学生
    student = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='grade_appeals',
        verbose_name='申诉学生'
    )

    # 申诉类型
    appeal_type = models.CharField(
        '申诉类型',
        max_length=50,
        choices=[
            ('score_error', '分数错误'),
            ('missing_grade', '缺少成绩'),
            ('grading_standard', '评分标准问题'),
            ('other', '其他'),
        ],
        default='other'
    )

    # 申诉理由
    reason = models.TextField('申诉理由')

    # 期望分数
    expected_score = models.DecimalField(
        '期望分数',
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        validators=[MinValueValidator(0)]
    )

    # 申诉状态
    status = models.CharField(
        '状态',
        max_length=20,
        choices=[
            ('pending', '待处理'),
            ('reviewing', '审核中'),
            ('accepted', '已接受'),
            ('rejected', '已拒绝'),
            ('resolved', '已解决'),
        ],
        default='pending'
    )

    # 处理人
    processed_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        related_name='processed_appeals',
        verbose_name='处理人',
        null=True,
        blank=True
    )

    # 处理时间
    processed_at = models.DateTimeField('处理时间', null=True, blank=True)

    # 处理结果
    result = models.TextField('处理结果', blank=True)

    # 是否需要重新评分
    needs_regrading = models.BooleanField('需要重新评分', default=False)

    class Meta:
        db_table = 'grade_appeals'
        verbose_name = '成绩申诉'
        verbose_name_plural = '成绩申诉'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['status']),
            models.Index(fields=['student']),
            models.Index(fields=['grade']),
        ]

    def __str__(self):
        return f"{self.student.real_name} - {self.get_appeal_type_display()}"

    def accept(self, processor, result_text=''):
        """接受申诉"""
        self.status = 'accepted'
        self.processed_by = processor
        self.processed_at = timezone.now()
        self.result = result_text
        self.save(update_fields=['status', 'processed_by', 'processed_at', 'result'])

    def reject(self, processor, result_text=''):
        """拒绝申诉"""
        self.status = 'rejected'
        self.processed_by = processor
        self.processed_at = timezone.now()
        self.result = result_text
        self.save(update_fields=['status', 'processed_by', 'processed_at', 'result'])


class GradeStatistics(TimeStampedModel):
    """
    成绩统计
    """
    # 关联考试
    examination = models.ForeignKey(
        'examination.Examination',
        on_delete=models.CASCADE,
        related_name='grade_statistics',
        verbose_name='考试',
        null=True,
        blank=True
    )

    # TODO: Implement courses app
    # course = models.ForeignKey(
    #     'courses.Course',
    #     on_delete=models.CASCADE,
    #     related_name='grade_statistics',
    #     verbose_name='课程',
    #     null=True,
    #     blank=True
    # )

    grade_sheet = models.OneToOneField(
        GradeSheet,
        on_delete=models.CASCADE,
        related_name='grade_statistics',
        verbose_name='成绩单',
        null=True,
        blank=True
    )

    # 统计日期范围
    start_date = models.DateField('开始日期', null=True, blank=True)
    end_date = models.DateField('结束日期', null=True, blank=True)

    # 统计数据
    total_students = models.PositiveIntegerField('总学生数', default=0)
    average_score = models.DecimalField('平均分', max_digits=6, decimal_places=2, null=True)
    median_score = models.DecimalField('中位数', max_digits=6, decimal_places=2, null=True)
    std_deviation = models.DecimalField('标准差', max_digits=6, decimal_places=2, null=True)
    variance = models.DecimalField('方差', max_digits=8, decimal_places=4, null=True)

    # 分数分布 (JSON格式)
    score_distribution = models.JSONField('分数分布', default=dict, blank=True)

    # 等级分布 (JSON格式)
    grade_distribution = models.JSONField('等级分布', default=dict, blank=True)

    # 班级对比 (JSON格式)
    class_comparison = models.JSONField('班级对比', default=dict, blank=True)

    # 历史趋势 (JSON格式)
    historical_trend = models.JSONField('历史趋势', default=dict, blank=True)

    # 创建者
    creator = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='grade_statistics',
        verbose_name='创建者'
    )

    class Meta:
        db_table = 'grade_statistics'
        verbose_name = '成绩统计'
        verbose_name_plural = '成绩统计'
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['examination']),
            # models.Index(fields=['course']),  # TODO: Add when courses app is implemented
            models.Index(fields=['start_date', 'end_date']),
        ]

    def __str__(self):
        if self.examination:
            return f"{self.examination.title} - 成绩统计"
        elif self.course:
            return f"{self.course.name} - 成绩统计"
        return "成绩统计数据"

    def calculate_class_comparison(self):
        """计算班级对比数据"""
        if not self.grade_sheet:
            return

        grades = self.grade_sheet.grades.all()
        class_data = {}

        for grade in grades:
            # 获取学生班级信息
            class_name = getattr(grade.student, 'class_name', '未知班级')

            if class_name not in class_data:
                class_data[class_name] = {
                    'students': [],
                    'count': 0,
                    'total_score': 0,
                    'passed_count': 0
                }

            class_data[class_name]['students'].append(float(grade.final_score or 0))
            class_data[class_name]['count'] += 1
            class_data[class_name]['total_score'] += float(grade.final_score or 0)

            if grade.is_passed:
                class_data[class_name]['passed_count'] += 1

        # 计算统计信息
        for class_name, data in class_data.items():
            if data['count'] > 0:
                data['average_score'] = data['total_score'] / data['count']
                data['pass_rate'] = (data['passed_count'] / data['count']) * 100

                scores = data['students']
                scores.sort()
                data['median_score'] = scores[len(scores) // 2] if scores else 0

                # 计算标准差
                if len(scores) > 1:
                    avg = data['average_score']
                    variance = sum((x - avg) ** 2 for x in scores) / len(scores)
                    data['std_dev'] = variance ** 0.5
                else:
                    data['std_dev'] = 0

        self.class_comparison = class_data
        self.save(update_fields=['class_comparison'])